在本系列文中,所有的程式碼以及測試都可以在 should-i-use-fp-ts 找到,今日的範例放在 src/day-16
並且有習題和測試可以讓大家練習。
接下來要介紹的 Do notation
函式是 apS
, 用於增加不依賴於 Do
內部屬性的純數值,以下是使用情境。
const example = pipe(
// { _tag: 'Some', value: {} }
O.Do,
// { _tag: 'Some', value: { a: 'tests' } }
O.apS('a', O.some('tests')),
// { _tag: 'Some', value: { a: 'tests', b: 1 } }
O.apS('b', O.some(1)),
// { _tag: 'Some', value: { a: 'tests', b: 1, c: 2 } }
O.apS('c', O.some(2)),
);
和 bind
的差別就只有在 Do notation
新增此屬性時,有沒有使用到 Do
內部屬性的必要。
const diff = pipe(
O.of(1), // { _tag: 'Some', value: 1 }
O.bindTo('x'), // { _tag: 'Some', value: { x: 1 } }
// apS only accept pure variable to be appended
// { _tag: 'Some', value: { x: 1, y: 'apS' } }
O.apS('y', O.of('apS')),
// bind can use the prop inside Do // x, y
// { _tag: 'Some', value: { x: 1, y: 'apS', z: '1 apS' } }
O.bind('z', ({ x, y }) => O.of(`${x} ${y}`)),
);
接著我們來實作 apS
的型別。
name
來作為 Do object
的 prop name(key)name
必須是 Do
尚未有的 keyfb
作為 [name]
這個 key
的 value
Do
來注入新的屬性export type ApS = <N extends string, A, B>(name: Exclude<N, keyof A>, fb: O.Option<B>) =>
<A>(fa: O.Option<A>) =>
O.Option<{ readonly [K in N | keyof A]: K extends keyof A ? A[K] : B }>;
接著實作函式 apS
,實作過程和 bind
非常相似,差別只有傳入的數值是純數值。
// use name = 'a', fb = O.some('tests'), fa = O.Do as example
const apS: ApS = (name, fb) => fa => pipe(
fa, // { _tag: 'Some', value: {} } (our Do object)
O.flatMap(a => pipe(
fb, // { _tag: 'Some', value: 'tests' } (our pure variable)
// { _tag: 'Some', value: { a: 'tests' } }
O.map(b => Object.assign({}, a, { [name]: b }) as any),
)),
); // { _tag: 'Some', value: { a: 'tests' } }
今天的主題在 should-i-use-fp-ts src/day-16
有習題和測試可以練習,大家可以嘗試自己能不能寫出自己的 apS
。